/**
 * @file	BidirectionalComm.c
 * @author	chipsea
 * @brief	
 * @version	0.1
 * @date	2021-01-07
 * @copyright Copyright (c) 2021, CHIPSEA Co., Ltd.
 * @note
 */

/*********************************************************************
 * INCLUDES
 */
#include "rf_phy_driver.h"
#include "global_config.h"
#include "OSAL.h"
#include "OSAL_PwrMgr.h"
#include "log.h"
#include "timer.h"
#include "BidirectionalComm.h"
#include "ll.h"
#include "ll_hw_drv.h"
#include "clock.h"
#include "gpio.h"
#include "flash.h"
#include "proprietary_rf.h"



/*********************************************************************
 * CONSTANTS
 */



#define DEFAULT_CRC_SEED                        (0x555555)

#define DEFAULT_WHITEN_SEED                     (0x37)
#define WHITEN_SEED_CH37                        (0x53)
#define WHITEN_SEED_CH38                        (0x33)
#define WHITEN_SEED_CH39                        (0x73)
#define WHITEN_OFF                              (0x00)

#define BLE_ADV_CHN37                           (02)
#define BLE_ADV_CHN38                           (26)
#define BLE_ADV_CHN39                           (80)


#define DEFAULT_SYNCWORD                        (0x8e5678d6)//(0x8e89bed6)

//header: bit[3:0]is PACKET header, bit[7:4] is packet sequence number
#define DEFAULT_TX_PKT_HEADER						0x00
#define DEFAULT_ACK_PKT_HEADER						0x03
#define DEFAULT_RX_PKT_HEADER						0x00

extern uint8 ll_hw_get_tr_mode(void);

/*********************************************************************
 * LOCAL VARIABLES
 */
uint8 BidirectionalComm_TaskID; // Task ID for internal task/event processing
//volatile uint32 phyWaitingIrq = FALSE;
uint8_t txPacketSeqNum;
uint8_t rxPacketSeqNum;
uint8_t send_buffer[RF_PKT_PAYLOAD_SIZE];
uint8_t send_buffer_len;
uint16_t send_cnt;

uart_data_t uart_rx_data;
uart_data_t uart_tx_data;

__ATTR_SECTION_SRAM__ void uart_receive_callback(uart_Evt_t* pev)
{
	switch(pev->type)
	{
		case UART_EVT_TYPE_RX_DATA:
		case UART_EVT_TYPE_RX_DATA_TO:
		{
			uint16_t i;
			for(i=0; i<pev->len; i++) {
				uart_rx_data.data[(uart_rx_data.wr+i)&(UART_BUF_SIZE-1)] = pev->data[i];
			}
			uart_rx_data.wr += pev->len;
			osal_set_event(BidirectionalComm_TaskID, USR_UART_RCV_DATA_EVT);
		}
		break;
		
		case UART_EVT_TYPE_TX_COMPLETED:
		break;
	}
}

__ATTR_SECTION_SRAM__ uint8_t rf_send_uart_data(void)
{
	uint16_t len, i;
	len = uart_rx_data.wr - uart_rx_data.rd;
	if(len > RF_PKT_PAYLOAD_SIZE - 6)
	{
		len = RF_PKT_PAYLOAD_SIZE - 6;
	}

	if(len > 0)		//there are uart data to send
	{
		for(i=0;i<len;i++)
		{
			send_buffer[6+i] = uart_rx_data.data[(uart_rx_data.rd++)&(UART_BUF_SIZE-1)];
		}
		send_buffer_len = 6+len;
		txPacketSeqNum++;
		rf_tx_buf_update(DEFAULT_TX_PKT_HEADER | (txPacketSeqNum<<4), send_buffer_len,  send_buffer);
		rf_tx_start();
		send_cnt++;
		return 1;
	}
	return 0;
}

__ATTR_SECTION_SRAM__ uint8_t rf_handler_callback(rfEvent_t *evt)
{
	uint8_t status = 0;
	uint16_t i;
	switch(evt->rfEvent)
	{
		case RF_EVT_RX_DONE:
			if((evt->header&0x0F) == DEFAULT_RX_PKT_HEADER)	
			{
				if((rxPacketSeqNum&0x0F) != (evt->header>>4))
				{
					rxPacketSeqNum = (evt->header>>4);
//					uart_tx_data.data[(uart_tx_data.wr++)&(UART_BUF_SIZE-1)] = evt->header;
//					uart_tx_data.data[(uart_tx_data.wr++)&(UART_BUF_SIZE-1)] = evt->length;
					//save receive data to UART buffer, ignore first 6 bytes, because it is MAC address
					for(i=6;i<evt->length;i++)
					{
						uart_tx_data.data[(uart_tx_data.wr++)&(UART_BUF_SIZE-1)] = evt->pPayload[i];
					}
					osal_set_event(BidirectionalComm_TaskID, USR_RF_RCV_DATA);
				}
				//send ACK information
				rf_tx_ack_update(DEFAULT_ACK_PKT_HEADER | (evt->header & 0xF0), 6, &send_buffer[0]);
				rf_tx_ack_start();
				status = 1;
				break;
			}
		case RF_EVT_TX_DONE:		
		case RF_EVT_RX_TIMEOUT:
		case RF_EVT_RX_PKT_ERR:	
			send_cnt = 0;
			if(uart_rx_data.wr != uart_rx_data.rd)
			{
				osal_set_event(BidirectionalComm_TaskID, RF_TRANSMIT_EVT);
			}
			else
			{
				rf_rx_start();
				status = 1;
			}			
			break;
		
		case RF_EVT_TRX_DONE:	
			if(((evt->header&0x0F) == DEFAULT_ACK_PKT_HEADER && (evt->header>>4) == (txPacketSeqNum&0x0F)) ||	//ACK packet is correct
				send_cnt >= RF_RETRANSMIT_CNT_LIMIT)			//extend send limit count, send new packet
			{
				if(send_cnt >= RF_RETRANSMIT_CNT_LIMIT)
				{
					LOG("R");
				}
				send_buffer_len = 0;

				send_cnt = 0;
				if(uart_rx_data.wr != uart_rx_data.rd)
				{
					osal_set_event(BidirectionalComm_TaskID, RF_TRANSMIT_EVT);
				}
				else
				{
					rf_rx_start();
					status = 1;
				}		
			}
			else	//ACK packet is error, so retransmit previous packet
			{
				osal_start_timerEx(BidirectionalComm_TaskID, RF_RETRANSMIT_EVT, RF_RETRANSMIT_TIME);
			}
			break;
			
		case RF_EVT_TRX_TIMEOUT:	
		case RF_EVT_TRX_PKT_ERR:	
			if(send_cnt >= RF_RETRANSMIT_CNT_LIMIT)			//extend send limit count, send new packet
			{
				send_buffer_len = 0;
				
				send_cnt = 0;
				if(uart_rx_data.wr != uart_rx_data.rd)
				{
					osal_set_event(BidirectionalComm_TaskID, RF_TRANSMIT_EVT);
				}
				else
				{
					rf_rx_start();
					status = 1;
				}					
			}
			else	//retransmit previous packet
			{
				osal_start_timerEx(BidirectionalComm_TaskID, RF_RETRANSMIT_EVT, RF_RETRANSMIT_TIME);
			}
			break;
	}
	return status;
}

/*********************************************************************
 * @fn      BidirectionalComm_Init
 *
 * @brief   Initialization function for the Simple BLE Peripheral App Task.
 *          This is called during initialization and should contain
 *          any application specific initialization (ie. hardware
 *          initialization/setup, table initialization, power up
 *          notificaiton ... ).
 *
 * @param   task_id - the ID assigned by OSAL.  This ID should be
 *                    used to send messages and set timers.
 *
 * @return  none
 */
void BidirectionalComm_Init(uint8 task_id)
{
	rfPktCfg_t pktCfg;
	rfPhyCfg_t phyCfg;
	
    BidirectionalComm_TaskID = task_id;
    JUMP_FUNCTION(BB_IRQ_HANDLER)                   =   (uint32_t)&RF_IRQHandler;		//set rf irq handeler
	
	HalUartRegister(UART0, uart_receive_callback);
	
    // read flash driectly becasue HW has do the address mapping for read Flash operation
    HalFlashRead(0x11001000,&send_buffer[0],6);		//device MAC address
	//
	rf_register_for_irq_callback(rf_handler_callback);
	//
	pktCfg.pktFmt = RF_PKT_FMT_1M;
	pktCfg.pduLen = (31+6);
	pktCfg.wtSeed = WHITEN_SEED_CH37;
	pktCfg.crcFmt = LL_HW_CRC_BLE_FMT;//LL_HW_CRC_BLE_FMT;LL_HW_CRC_NULL
	pktCfg.crcSeed = DEFAULT_CRC_SEED;
	pktCfg.syncWord = DEFAULT_SYNCWORD;
	rf_hw_pktFmt_config(&pktCfg);
	//
    phyCfg.bleEnable = false;
	phyCfg.autoAck = 1;
	phyCfg.rfChn = BLE_ADV_CHN37;
	phyCfg.rxOnlyTO = 10*1000;//us
	phyCfg.rxAckTO = 500;//us
	rf_hw_phy_config(&phyCfg);
	
	rf_tx_ack_update(DEFAULT_ACK_PKT_HEADER, 6, &send_buffer[0]);
	
	rf_rx_start();	//start receive
}

/*********************************************************************
 * @fn      BidirectionalComm_ProcessEvent
 *
 * @brief   Application Task event processor.  This function
 *          is called to process all events for the task.  Events
 *          include timers, messages and any other user defined events.
 *
 * @param   task_id  - The OSAL assigned task ID.
 * @param   events - events to process.  This is a bit map and can
 *                   contain more than one event.
 *
 * @return  events not processed
 */
uint16 BidirectionalComm_ProcessEvent(uint8 task_id, uint16 events)
{
    VOID task_id;
	rfPhyStatus_t status;
	
	//When retransmit, it should change the packet content, otherwise it maybe transmit error.
	if( events & RF_RETRANSMIT_EVT )
	{
		if(send_buffer_len > 0)
		{
			rf_tx_buf_update(DEFAULT_TX_PKT_HEADER | (txPacketSeqNum<<4), send_buffer_len,  send_buffer);
			rf_tx_start();
			send_cnt++;
			if(send_cnt >= 25)
			{
				LOG("E:%x,%x,%x ", txPacketSeqNum, send_buffer_len, send_buffer[6]);
			}
		}
		return(events ^ RF_RETRANSMIT_EVT);
	}
	
	if( events &RF_TRANSMIT_EVT )
	{
		status = rf_phy_status_get();
		if(status == RF_PHY_ST_RX_ONLY)
		{
			rf_stop();
			//don't clear event, because it need to process next time
		}
		else if(status == RF_PHY_ST_IDLE && send_buffer_len == 0)
		{
			send_cnt = 0;
			if(rf_send_uart_data() == 0)	//RF don't send uart data, RF need to goto receive mode
			{
				rf_rx_start();
			}
			return(events ^ RF_TRANSMIT_EVT);
		}
	}
	
	if( events & USR_UART_RCV_DATA_EVT )
	{
		status = rf_phy_status_get();
		if(status == RF_PHY_ST_RX_ONLY)
		{
			rf_stop();
			//don't clear event, because it need to process next time
		}
		else if(status == RF_PHY_ST_IDLE && send_buffer_len == 0)
		{
			send_cnt = 0;
			if(rf_send_uart_data() == 0)	//RF don't send uart data, RF need to goto receive mode
			{
				rf_rx_start();
			}
			return(events ^ RF_TRANSMIT_EVT);
		}
	}
	
	if( events & USR_RF_RCV_DATA )
	{
		while(uart_tx_data.rd != uart_tx_data.wr)
		{
			HalUartSendByte(UART0, uart_tx_data.data[(uart_tx_data.rd++)&(UART_BUF_SIZE-1)]);
		}
		return(events ^ USR_RF_RCV_DATA);
	}

    return 0;
}

/**************************************************************************************************
 * @fn          main
 *
 * @brief       Start of application.
 *
 * @param       none
 *
 * @return      none
 **************************************************************************************************
 */
int app_main(void)
{

    /* Initialize the operating system */
    osal_init_system();

    osal_pwrmgr_device(PWRMGR_BATTERY);

    /* Start OSAL */
    osal_start_system(); // No Return from here

    return 0;
}
/*********************************************************************
*********************************************************************/
